package com.mall.service.data;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;

import com.mall.core.Customer;
import com.mall.core.Indentifiable;
import com.mall.core.Visitor;
import com.mall.implementation.CustomerImpl;
import com.mall.util.StringWrapper;

// An object that stores data objects by serializing the object in to files.
// The Files by default have the same name as the class of the object with the index number of the file.
// This object also retrieves the serialized stored data objects and returns the objects serialized
public class DataRecorder<ifobj extends Serializable & Indentifiable> implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static int index = 0;
	private String objectname = null;
	private String filename_of_serialed_object = null;
	private boolean serialized = false;

	
	public boolean storeData(ifobj tobeserialized) {
		ArrayList<String> nameoffiles = new ArrayList<String>();
		nameoffiles = retrieveFileNames(tobeserialized);
		
		index = unSerializeindex();
		
		// java reflection to get the object name
		Class<? extends Serializable> clObj;
		clObj = tobeserialized.getClass();
		objectname = clObj.getSimpleName();
	


		
		if (tobeserialized.getId() == 0) {

			index++;
			serializeindex(index);
			tobeserialized.setId(index);
			filename_of_serialed_object = objectname + tobeserialized.getId()
					+ ".ser";
			nameoffiles.add(filename_of_serialed_object);
			System.out.println(filename_of_serialed_object);
			System.out.println("This object Exist");
		} else {

			filename_of_serialed_object = objectname + tobeserialized.getId()
					+ ".ser";

			System.out.println(filename_of_serialed_object);
			System.out.println("trying to creat object");
			
		}


		// Serialization begins here
		FileOutputStream fos = null;
		FileOutputStream fosnf = null;
		ObjectOutputStream out = null;

		try {
			fos = new FileOutputStream(filename_of_serialed_object);
			fosnf = new FileOutputStream(objectname + ".ser");
			out = new ObjectOutputStream(fos);
			out.writeObject(tobeserialized);
			out = new ObjectOutputStream(fosnf);
			out.writeObject(nameoffiles);
			out.close();
			serialized = true;
		} catch (IOException ex) {
			serialized = false;
			ex.printStackTrace();
		}

		return this.serialized;
	}
	private void  serializeindex(Integer lastIndex){
		
		// Serialization begins here
		FileOutputStream fos = null;
		ObjectOutputStream out = null;

		try {
			fos = new FileOutputStream("index"+".ser");
			out = new ObjectOutputStream(fos);
			out.writeObject(lastIndex);
			out.close();
			serialized = true;
		} catch (IOException ex) {
			serialized = false;
			ex.printStackTrace();
		}
	}
	
	private Integer unSerializeindex(){
		Integer lastIndex = null;
		// Serialization begins here
		FileInputStream fis = null;
		ObjectInputStream in = null;

		try {
			fis = new FileInputStream("index"+".ser");
			in = new ObjectInputStream(fis);
			lastIndex = (Integer) in.readObject();
			in.close();
			serialized = true;
		} catch (IOException ex) {
			serializeindex(index++);
			serialized = false;
			}
		  catch(NullPointerException ex){System.err.print("Creating Index for the First time");}

		 catch (ClassNotFoundException ex) {
			ex.printStackTrace();
		}
		return lastIndex;
		
	}

	@SuppressWarnings("unchecked")
	public ifobj retrieveData(ifobj retrievableobject) {
		ifobj retrievedobject = retrievableobject;
		FileInputStream fis = null;
		ObjectInputStream in = null;
		ObjectOutputStream out = null;
		FileOutputStream fos = null;
		try {
			fis = new FileInputStream(retrievableobject.getClass()
					.getSimpleName() + retrievableobject.getId() + ".ser");
			in = new ObjectInputStream(fis);
			retrievedobject = (ifobj) in.readObject();
			in.close();
			fos = new FileOutputStream(retrievableobject.getClass()
					.getSimpleName() + retrievableobject.getId() + ".ser");
			out = new ObjectOutputStream(fos);
			out.writeObject(retrievedobject);
			out.close();
		} catch (IOException ex) {
			ex.printStackTrace();
			System.out.println("Try again");
		} catch (ClassNotFoundException ex) {
			ex.printStackTrace();
		}
		return retrievedobject;
	}

	@SuppressWarnings("unchecked")
	public ifobj retrieveDatabyfilename(String recordfile) {
		ifobj retrievedobject = null;
		FileInputStream fis = null;
		ObjectInputStream in = null;
		ObjectOutputStream out = null;
		FileOutputStream fos = null;
		try {

			fis = new FileInputStream(recordfile);
			in = new ObjectInputStream(fis);
			retrievedobject = (ifobj) in.readObject();
			in.close();
			fos = new FileOutputStream(recordfile);
			out = new ObjectOutputStream(fos);
			out.writeObject(retrievedobject);
			out.close();
		} catch (IOException ex) {
			ex.printStackTrace();
			System.out.println("Try again");
		} catch (ClassNotFoundException ex) {
			ex.printStackTrace();
		}
		return retrievedobject;
	}

	@SuppressWarnings("unchecked")
	public ArrayList<String> retrieveFileNames(ifobj retrievableobject) {

		Class<? extends Serializable> clObj = retrievableobject.getClass();
		ArrayList<String> retrievedobject = null;
		objectname = clObj.getSimpleName();
		FileInputStream fis = null;
		FileOutputStream fos = null;
		ObjectInputStream in = null;
		ObjectOutputStream out = null;
		try {

			fis = new FileInputStream(objectname + ".ser");
			in = new ObjectInputStream(fis);
			retrievedobject = (ArrayList<String>) in.readObject();
			in.close();
			fos = new FileOutputStream(objectname + ".ser");
			out = new ObjectOutputStream(fos);
			out.writeObject(retrievedobject);
			out.close();
		} catch (IOException ex) {
			ex.printStackTrace();
			System.out.println("Try again");
		} catch (ClassNotFoundException ex) {
			ex.printStackTrace();
		}
		return retrievedobject;
	}
	
	public static void main(String[] args) {

		DataRecorder<CustomerImpl> receiptrecorder = new DataRecorder<CustomerImpl>();
		CustomerImpl rec1 = new CustomerImpl();
		rec1.setUserName(new StringWrapper("amos"));
		rec1.setPassword(new StringWrapper("jeus1"));
		
		//CustomerImpl rec2 = new CustomerImpl();
		//rec2.setUserName(new StringWrapper("amos"));
		//rec2.setPassword(new StringWrapper("jsus1"));
		
		receiptrecorder.storeData(rec1);
	//	receiptrecorder.storeData(rec2);
		System.out.println("-------------------------------1----------------------------");
		System.out.println(receiptrecorder.retrieveData(rec1).getUserName().getNOTModifiedString());
		System.out.println(receiptrecorder.retrieveData(rec1).getPassword().getNOTModifiedString());
		System.out.println("-----------------------------------------------------------------");
		System.out.println("-------------------------------2--------------------------------");
		//System.out.println(receiptrecorder.retrieveData(rec2).getUserName().getNOTModifiedString());
		//System.out.println(receiptrecorder.retrieveData(rec2).getPassword().getNOTModifiedString());
		System.out.println("-----------------------------------------------------------------");
		for( String record : receiptrecorder.retrieveFileNames(rec1)){
			System.out.println(receiptrecorder.retrieveFileNames(rec1));
		}
	}

}
